#include "CMSInterface.h"


DOUBLE_BASE::DOUBLE_BASE()
{
	for(int i = 0 ; i < 2 ; i ++)
	{
		dValue[i] = 0.0;
	}
}

DOUBLE_BASE::DOUBLE_BASE(double d1 , double d2)
{
	dValue[0] = d1;
	dValue[1] = d2;
}

DOUBLE_BASE::DOUBLE_BASE(const DOUBLE_BASE& db)
{
	for(int i = 0 ; i < 2 ; i ++)
	{
		this->dValue[i] = db.dValue[i];
	}
}

bool operator == (const DOUBLE_BASE & db1, const DOUBLE_BASE & db2) 
{
	return (
		db1.dValue[0] == db2.dValue[0]
		&& db1.dValue[1] == db2.dValue[1]
	);
} 


const DOUBLE_BASE& DOUBLE_BASE::operator=(const DOUBLE_BASE& db) 
{
	if (this != &db) 
	{
		for(int i = 0 ; i < 2 ; i ++)
		{
			this->dValue[i] = db.dValue[i];
		}
	}
	return *this;
}


const _TIME& _TIME::operator+=( _TIME& t) 
{
	this->SetDuration( this->GetDuration() + t.GetDuration());
	return *this;
}


_OBJ_INFO::_OBJ_INFO()
{ 
	type = _EFFECT;

	alpha = 0.0;	
	rotation = 0.0;
	obj_path = "";
	sound_path = "";
	animation = false;

	blending = "";
	opacity = 0.0;

}


_OBJ_INFO::_OBJ_INFO(const _OBJ_INFO& o)
{
	this->type = o.type;
	this->obj_path = o.obj_path;
	this->sound_path = o.sound_path;

	this->time = o.time;;
	this->pos = o.pos;
	this->size = o.size;

	this->alpha = o.alpha;
	this->rotation = o.rotation;

	this->animation = o.animation;

	this->blending = o.blending;
	this->opacity = o.opacity;
}

_OBJ_INFO::_OBJ_INFO(const std::string& effect_path , const std::string& sound_path , const _TIME& t , const _POSITION& p , const _SIZE& s , const double a , const double r)
{
	type = _EFFECT; 

	this->obj_path = effect_path;
	this->sound_path = sound_path;

	time = t;
	pos = p;
	size = s;

	alpha = a;
	rotation = r;

	animation = false;


}

_OBJ_INFO::_OBJ_INFO(const std::string& filter_path , const std::string& blending , const double opacity)
{
	this->type = _BLEND;

	this->obj_path = filter_path;
	this->blending = blending;
	this->opacity = opacity;

	this->animation = false;
}

_OBJ_INFO::_OBJ_INFO(const std::string& curve_path)
{
	this->type = _CURVE;
	this->obj_path = curve_path;
}


void _OBJ_INFO::SetAnimationTmpFileName(const int width , const int height , const std::string& filename)
{
	this->type = _TEMP; 
	this->obj_path =  Settings::GetSettings()->TMP_DIR + filename;

	this->pos = _POSITION(width/2 , height/2);

	this->size = _SIZE(width , height);

	this->rotation = 0.0;	
	animation = true;
}

const _OBJ_INFO& _OBJ_INFO::operator=(const _OBJ_INFO& o) 
{
	if (this != &o) 
	{
		this->type = o.type;

		this->obj_path = o.obj_path;
		this->sound_path = o.sound_path;

		this->time = o.time;;
		this->pos = o.pos;
		this->size = o.size;	

		this->alpha = o.alpha;
		this->rotation = o.rotation;

		this->animation = o.animation;

		this->blending = o.blending;
		this->opacity = o.opacity;

	}
	return *this;
}

int MATH::DivideVectorBySize(const int limit_size , const string_vector& org , std::vector<string_vector>& out)
{
	out.clear();

	int div = org.size() / limit_size;
	int remain = org.size() % limit_size;

	int start_index = 0;
	for(int i = 0 ; i < div ; i ++)
	{
		string_vector tmp;
		tmp.insert(tmp.begin() , org.begin() + start_index , org.begin() + start_index + limit_size);
		out.push_back(tmp);

		start_index += limit_size;
	}

	if(remain > 0)
	{
		string_vector tmp;
		tmp.insert(tmp.begin() , org.begin() + start_index , org.end());
		out.push_back(tmp);

	}

	return out.size();

}



std::string MATH::ConvertRGB2Hex(int r , int g , int b)
{
	std::string hex = "0x";
	std::string buf;

	buf = ConvertDec2Hex(r);
	while(buf.length() <2 )
		buf = std::string("0") + buf;
	hex += buf;

	buf = ConvertDec2Hex(g);
	while(buf.length() <2 )
		buf = std::string("0") + buf;
	hex += buf;

	buf = ConvertDec2Hex(b);
	while(buf.length() <2 )
		buf = std::string("0") + buf;
	hex += buf;

	return hex;

}


_SIZE MATH::GetRotationSize( _SIZE& org_size , const double rotation)
{
	return _SIZE(
		fabs(org_size.GetWidth() * cos(rotation)) + fabs(org_size.GetHeight() * sin(rotation))
		, fabs(org_size.GetWidth() * sin(rotation)) + fabs(org_size.GetHeight() * cos(rotation))
		);
}


void MATH::ReplaceAll (std::string& strSrc, const std::string& strFind, const std::string& strDest)   
 {   
	 std::size_t j;   
   
	 while ((j = strSrc.find(strFind)) != std::string::npos)   
         strSrc.replace(j, strFind.length(), strDest);   
 }


void MATH::ConvertFilterPath(std::string & str)
{
	MATH::ReplaceAll(str , "\\" , "/");
	MATH::ReplaceAll(str , ":" , "\\?");
	MATH::ReplaceAll(str , "?" , ":");
}

bool MATH::IsSameExt(std::string path , std::string ext)
{
	transform(path.begin(), path.end(), path.begin(), tolower);
	transform(ext.begin(), ext.end(), ext.begin(), tolower);

	return path.find(ext) == path.length() - ext.length(); 
}

bool MATH::IsImage(const std::string& path)
{
	if(IsSameExt(path , ".png"))
		return true;

	if(IsSameExt(path , ".jpg"))
		return true;

	if(IsSameExt(path , ".jpeg"))
		return true;

	if(IsSameExt(path , ".tiff"))
		return true;

	if(IsSameExt(path , ".gif"))
		return true;

	if(IsSameExt(path , ".bmp"))
		return true;
	
	return false;
}

bool MATH::IsMovie(const std::string& path)
{
	if(IsSameExt(path , ".mov"))
		return true;

	if(IsSameExt(path , ".mp4"))
		return true;
	
	return false;
}

double MATH::Truncate(double value , int float_size)
{
	if(float_size < 0)
		return value;

	double mul = 1.0;
	for(int i = 0 ; i < float_size; i ++)
	{
		mul *= 10.0;
	}

	return (double)(int(value * mul)) / mul;
}

std::string MATH::CreateUUID()
{
	ACE_Utils::UUID uuid;
	ACE_Utils::UUID_GENERATOR::instance ()->generate_UUID (uuid);

	return uuid.to_string()->c_str();
}

std::string MATH::GetNowString()
{
 	int year , month , day;
	GetDate(year , month , day , 0);
	int hour , min , sec;
	GetTime(hour , min , sec);

	char str[30];
	sprintf(str , "%04d-%02d-%02d %02d:%02d:%02d" , year , month , day , hour , min , sec);
	return str;
}

std::string MATH::GetDatePathString(const bool storage , const int pass)
{
	int year , month , day;
	GetDate(year , month , day , pass);

	char buf[20];
	memset(buf , 0x00 , sizeof(buf));

	if(storage)
	{
		sprintf(buf , "/%d/%02d/%02d/" , year , month , day);
	}
	else
	{
#ifdef ACE_WIN32
	sprintf(buf , "\\%d\\%02d\\%02d\\" , year , month , day);
#else
	sprintf(buf , "/%d/%02d/%02d/" , year , month , day);
#endif
	}

	return buf;

}

std::string MATH::GetDateLogFileName(const int pass)
{
	int year , month , day;
	GetDate(year , month , day , pass);

	char buf[20];
	memset(buf , 0x00 , sizeof(buf));
#ifdef ACE_WIN32
	sprintf(buf , "%d%02d%02d.csv" , year , month , day);
#else
	sprintf(buf , "%d%02d%02d.csv" , year , month , day);
#endif

	return buf;
}

void MATH::GetDate(int& year , int& month , int& day , const int pass)
{
	time_t end = time(NULL);

	end += pass * (60*60*24); 


	struct tm  ti = *localtime(&end);



	year = ti.tm_year+1900;
	month = ti.tm_mon+1;
	day = ti.tm_mday;
}

void MATH::GetTime(int& hour , int& min , int& sec)
{
	time_t end = time(NULL);
	struct tm  ti = *localtime(&end);


	hour = ti.tm_hour;
	min = ti.tm_min;
	sec = ti.tm_sec;
}





int MATH::round(const double dv)
{
	int  b;
	if(fabs(dv) - abs((int)dv) >= 0.5)
	{
		if(dv > 0)
			b = (int)dv + 1;
		else
			b = (int)dv - 1;

	}
	else
		b = (int)dv;

	return b;
}






int MATH::GetPassedSecFromString(const std::string& time_str)
{
	int start = 0;
	std::string year , mon , day , hour , min , sec;

	year = time_str.substr(0 , 4);		start += 4+1;
	mon = time_str.substr(start , 2); 	start += 2+1;
	day = time_str.substr(start , 2);	start += 2+1;

	hour = time_str.substr(start , 2);	start += 2+1;
	min = time_str.substr(start , 2);	start += 2+1;
	sec = time_str.substr(start , 2);

	struct tm t;
	t.tm_year = atoi(year.c_str()) - 1900; 
	t.tm_mon = atoi(mon.c_str()) - 1; 
	t.tm_mday = atoi(day.c_str());

	t.tm_hour = atoi(hour.c_str());
	t.tm_min = atoi(min.c_str());
	t.tm_sec = atoi(sec.c_str());


	time_t launched = mktime(&t);

	time_t tt = time(NULL);
	struct tm *gtm = gmtime(&tt);
	time_t now = mktime(gtm);

	return  now - launched;
}


int MATH::GetPassedMinInLastHourFromString(const std::string& time_str)
{
	int passed_sec = GetPassedSecFromString(time_str);

	int passed_min = passed_sec / 60;
	if(passed_sec % 60 > 0)
		passed_min ++;

	return passed_min % 60;
}






std::vector<_PROCESS_INFO> PROCESS::g_VecPid;
ACE_Thread_Mutex	PROCESS::g_ProcessLock;	

void PROCESS::AddPid(int pid)
{
	g_ProcessLock.acquire();

	g_VecPid.push_back(pid);

	g_ProcessLock.release();
}

#ifndef ACE_WIN32
int PROCESS::handle_signal(int signum)
{
	printf("catch signal[%d]\n" , signum);

	Clear();

	return 0;
}

void PROCESS::InitSignal()
{
	ACE_Sig_Set sigset;

    sigset.sig_add (SIGTERM);

	ACE_Sig_Action sa (sigset, (ACE_SignalHandler) handle_signal);
	ACE_UNUSED_ARG (sa);
}
#endif

void PROCESS::DelPid(int pid)
{
	g_ProcessLock.acquire();

	std::vector<_PROCESS_INFO>::iterator pos = std::find(g_VecPid.begin() , g_VecPid.end() , pid);
	ACE_ASSERT(pos != g_VecPid.end()); 

	if(pos  != g_VecPid.end())
	{
		g_VecPid.erase(pos);
	}

	g_ProcessLock.release();

}


void PROCESS::Clear()
{

	g_ProcessLock.acquire();

	if(g_VecPid.size() > 0)
	{
		printf("close all children process\n");
		ACE_Process_Manager* pm = ACE_Process_Manager::instance ();
		if(pm)
		{
			for(int i = 0 ; i < g_VecPid.size() ; i ++)
			{
				if( 0 == pm->terminate(g_VecPid[i].pid))
				{
					printf("process [%d]  : terminated!\n" , g_VecPid[i].pid);
				}
				else
				{
					printf("process [%d]  : failed to terminate!\n" , g_VecPid[i].pid);
				}
			}

		}

	}

	g_ProcessLock.release();

}

int PROCESS::svc()
{
	while(!stop)
	{
		sleep(Settings::GetSettings()->JOB_CHECK_DELAY);

		g_ProcessLock.acquire();

		ACE_Process_Manager* pm = ACE_Process_Manager::instance ();
		if(pm)
		{
			for(int i = 0 ; i < g_VecPid.size() ; i ++)
			{
				_PROCESS_INFO * info = &g_VecPid[i];
				if(info->GetElapsedSec() >= Settings::GetSettings()->MAX_PROCESS_TIME * 60)
				{
					if( 0 == pm->terminate(info->pid))
					{
						printf("process [%d]  : timeover - terminated!\n" , info->pid);
					}
					else
					{
						printf("process [%d]  : timeover - failed to terminate!\n" , info->pid);
					}
				}
			}
		}

		g_ProcessLock.release();
	}

	return 0;
}



_RESULT_TYPE PROCESS::Execute(_PROCESS_TYPE type ,const std::string& cmd, const bool noOutput )
{
	_RESULT_TYPE ret = _SUCCESS;

	if(_OS_CMD == type)
	{
		int r = -1;
		if(noOutput)
		{
#ifdef ACE_WIN32
			r = system((cmd + " >nul 2>&1").c_str());
#else
			r = system((cmd + " >/dev/null 2>&1").c_str());
#endif 
		}
		else
		{
			r = system(cmd.c_str());
		}

		if(r !=0)
		{
			ret = _INVALID_CMD;
			LOG::PushProcessLog(_ERROR , std::string("invalid command(os command) : ") + cmd);
		}

		return ret;
	}

	ACE_Process_Options options(1 , cmd.length() + 1);
	options.command_line (cmd.c_str());


	ACE_Process_Manager* pm = ACE_Process_Manager::instance ();
	pid_t pid = pm->spawn(options);

	if(-1 == pid)
	{
		LOG::PushProcessLog(_ERROR , std::string("invalid command(single file exe) : ") + cmd);
		ret = _INVALID_CMD;
	}
	else
	{
		AddPid(pid);

		ACE_exitcode status = -1;
		pm->wait(pid , &status);	

		DelPid(pid);

		if(status != 0)
		{
			LOG::PushProcessLog(_ERROR , std::string("execute process error(single file exe) : ") + cmd);
			ret = _FAIL;
		}

	}

	return ret;

}

_RESULT_TYPE PROCESS::Execute2(_PROCESS_TYPE type ,const std::string& cmd, const bool noOutput )
{
	_RESULT_TYPE ret = _SUCCESS;

	if(_OS_CMD == type)
	{
		int r = -1;
		if(noOutput)
		{
#ifdef ACE_WIN32
			r = system((cmd + " >nul 2>&1").c_str());
#else
			r = system((cmd + " >/dev/null 2>&1").c_str());
#endif 
		}
		else
		{
			r = system(cmd.c_str());
		}

		if(r !=0)
		{
			ret = _INVALID_CMD;
			LOG::PushProcessLog(_ERROR , std::string("invalid command(os command) : ") + cmd);
		}

		return ret;
	}

	ACE_Process_Options options(1 , cmd.length() + 1);
	options.command_line (cmd.c_str());


	ACE_Process_Manager* pm = ACE_Process_Manager::instance ();
	pid_t pid = pm->spawn(options);

	if(-1 == pid)
	{
		LOG::PushProcessLog(_ERROR , std::string("invalid command(single file exe) : ") + cmd);
		ret = _INVALID_CMD;
	}
	else
	{
		AddPid(pid);

		ACE_exitcode status = -1;
		pm->wait(pid , &status);	

		DelPid(pid);

		if(status != 0)
		{	
			ret = _FAIL;
		}

	}

	return ret;

}

_RESULT_TYPE PROCESS::Execute(const std::string& cmd, std::string& outstring)
{
	_RESULT_TYPE ret = _SUCCESS;


	ACE_Process_Options options(1 , cmd.length() + 1);
	options.command_line (cmd.c_str());

	ACE_HANDLE fd[2];


#ifdef ACE_WIN32
	if (ACE_OS::pipe(fd) == -1)   
	{
		LOG::PushProcessLog(_ERROR , std::string("create pipe error : ") + cmd);
		return _FAIL;
	}
#else
	ACE_Pipe pipe(fd);
#endif

	options.set_handles(fd[0] , fd[1] );

	ACE_Process_Manager* pm = ACE_Process_Manager::instance ();
	pid_t pid = pm->spawn(options);

	if(-1 == pid)
	{
		LOG::PushProcessLog(_ERROR , std::string("create process error(get output) : ") + cmd);
		ret = _INVALID_CMD;
	}
	else
	{

		if (ACE_OS::close(fd[1]) == -1) 
		{
			LOG::PushProcessLog(_ERROR , std::string("stdout pipe close error : ") + cmd);
			ret = _FAIL;
		}
		else
		{
			AddPid(pid);

			options.release_handles();

			outstring = "";
			char outbuf[MAX_BUFFER + 1] = {0,}; 

			memset(outbuf , 0x00 , sizeof(outbuf));
			while(ACE_OS::read(fd[0], outbuf, MAX_BUFFER) > 0) 
			{
				outstring += outbuf;
				memset(outbuf , 0x00 , sizeof(outbuf));
			}   

			ACE_exitcode status = -1;
			pm->wait(pid , &status);	


			DelPid(pid);

			if(status != 0)
			{
				LOG::PushProcessLog(_ERROR , std::string("execute process error(get output) : ") + cmd);
				ret = _FAIL;
			}

			if (ACE_OS::close(fd[0]) == -1) 
			{
				LOG::PushProcessLog(_ERROR , std::string("stdin pipe close error : ") + cmd);
				ret = _FAIL;
			}

		}

	}


#ifndef ACE_WIN32
	pipe.close();
#endif

	return ret;

}

void PROCESS::DeleteTempFiles(const std::string& job_id)
{
	if(Settings::IsDebugMode())
		return;


	std::string cmd;

	if(job_id.length() > 0)
	{
		cmd = std::string(DELETE_CMD) + " " + Settings::GetSettings()->TMP_DIR + job_id + "*";
	}
	else
	{

#ifdef ACE_WIN32
		cmd = std::string(DELETE_CMD) + " /Q " +  Settings::GetSettings()->TMP_DIR +"*";
#else
		cmd = std::string(DELETE_CMD) + " -f " +  Settings::GetSettings()->TMP_DIR +"*";
#endif
	}


	PROCESS::Execute(_OS_CMD , cmd);
}

int PROCESS::GetFilesInDirectory(std::vector<std::string>& vecFiles , const std::string& directory , const std::string& search_string)
{
	std::string list_file_path = std::string(Settings::GetSettings()->TMP_DIR) + LIST_FILE;

#ifdef ACE_WIN32
	std::string cmd = "dir " + directory + "\\" + search_string + " /b > " + list_file_path;
#else
	std::string cmd = "ls " + directory + "/" + search_string + " | xargs -n1 basename > " + list_file_path;
#endif

	if(system(cmd.c_str()) != 0)
		return 0;

	FILE * f = fopen(list_file_path.c_str() , "r");
	if(!f)
		return 0;

	char buf[1024];

	while(!feof(f))
	{
		fscanf(f , "%s" , buf);
		if( strlen(buf) > 0)
		{
			vecFiles.push_back(buf);
		}

		memset(buf , 0x00 , sizeof(buf));
	}



	return vecFiles.size();
	
} 




LOG LOG::g_Log;


int LOG::Insert(const _LOG_DATA&ld)
{
	int size = 0;
	m_Lock.acquire();
	m_vecLogData.push_back(ld);
	size = m_vecLogData.size();
	m_Lock.release();

	return size;
}

bool LOG::InsertLogData(const _LOG_DATA& ld)
{
	return g_Log.Insert(ld);
}

int LOG::svc()
{

	while(!m_bStop)
	{
		std::vector<_LOG_DATA> v;

		m_Lock.acquire();

		v = m_vecLogData;		
		m_vecLogData.clear();	

		m_Lock.release();


		for(int i = 0 ; i < v.size() ; i ++)
		{
			_LOG_DATA& ld = v[i];

			switch(ld.type)
			{
			case _PROCESS_LOG:
				WriteProcessLog(ld.mode , ld.str_value[0]);
				break;
			case _JOB_LOG:
				WriteJobLog(ld.mode , ld.str_value[0], ld.double_value[0] , ld.int_value[0] , ld.str_value[1]);
				break;
			case _EC2_LOG:
				WriteEC2Log(ld.mode , ld.str_value[0], ld.bool_value[0]);
				break;
			case _SCALING_LOG:
				WriteScalingLog(ld.mode , ld.int_value[0], ld.int_value[1], ld.int_value[2]);
				break;
			case _OBJECT_LOG:
				WriteObjectLog(ld.str_value[0], ld.str_value[1], ld.str_value[2], ld.str_value[3]);
				break;
			default:
				ACE_ASSERT(false);
			}

		}

		if(v.size() == 0 && !m_bStop)
		{
			sleep(Settings::GetSettings()->QUEUE_DELAY);
		}

	}

	return 0;
}



int LOG::PushProcessLog(const _LOG_MODE mode , const std::string& content)
{
	if(g_Log.m_bStop)
		return true;

	if(_REQUIRED == mode)
	{
		LOG::SendSMS(content , mode);

	}
	else if(_ERROR == mode) 
	{
		LOG::SendSMS("CHECK PROCESS LOG" , mode);

	}

	if(!Settings::IsDebugMode() && _INFO == mode)
	{
		return true;
	}

	_LOG_DATA ld;
	ld.type = _PROCESS_LOG;
	ld.mode = mode;
	ld.str_value[0] = content;

	return InsertLogData(ld);
}

int LOG::PushJobLog(const _LOG_MODE mode ,const std::string& job_id , const std::string& content)
{
	if(g_Log.m_bStop)
		return true;

	if(_ERROR == mode)
	{
		LOG::SendSMS("JOB["+job_id + "] ", _ERROR);
	}

	if(!Settings::IsDebugMode() && _INFO == mode)
	{
		return true;
	}

	_LOG_DATA ld;
	ld.type = _JOB_LOG;
	ld.mode = mode;
	ld.str_value[0] = job_id;
	ld.str_value[1] = content;
	ld.double_value[0] = 0.0;
	ld.int_value[0] = 0;

	return InsertLogData(ld);
}

int LOG::PushObjectLog(const std::string& job_id , const std::string& filterId, const std::string& effectIdList, const std::string& soundId)
{
	if(g_Log.m_bStop)
		return true;

	
	_LOG_DATA ld;
	ld.type = _OBJECT_LOG;
	ld.str_value[0] = job_id;
	ld.str_value[1] = filterId;
	ld.str_value[2] = effectIdList;
	ld.str_value[3] = soundId;

	return InsertLogData(ld);
}

int LOG::PushJobLog(const _LOG_MODE mode , const std::string& job_id , const double duration , const int rendering_time)
{
	if(g_Log.m_bStop)
		return true;

	if(!Settings::IsDebugMode() && _INFO == mode)
	{
		return true;
	}

	_LOG_DATA ld;
	ld.type = _JOB_LOG;
	ld.mode = mode;
	ld.str_value[0] = job_id;
	ld.str_value[1] = "SUCCEEDED";
	ld.double_value[0] = duration;
	ld.int_value[0] = rendering_time;

	return InsertLogData(ld);
}

int LOG::PushEC2Log(const _LOG_MODE mode , const std::string& ec2_id , const bool start)
{
	if(g_Log.m_bStop)
		return true;

	if(!Settings::IsDebugMode() && _INFO == mode)
	{
		return true;
	}

	_LOG_DATA ld;
	ld.type = _EC2_LOG;
	ld.mode = mode;
	ld.str_value[0] = ec2_id;
	ld.bool_value[0] = start;

	return InsertLogData(ld);
}
int LOG::PushScalingLog(const _LOG_MODE mode , const int waiting , const int changed , const int total)
{
	if(g_Log.m_bStop)
		return true;

	char tmp[200];
	sprintf(tmp , "waiting count : %d , change instance : %d , total instance : %d" , waiting, changed , total);
	LOG::SendSMS(tmp , mode);

	if(!Settings::IsDebugMode() && _INFO == mode)
	{
		return true;
	}

	_LOG_DATA ld;
	ld.type = _SCALING_LOG;
	ld.mode = mode;
	ld.int_value[0] = waiting;
	ld.int_value[1] = changed;
	ld.int_value[2] = total;

	return InsertLogData(ld);
}

bool LOG::SendSMS(const std::string& msg , const _LOG_MODE mode )
{
	std::string group_code = Settings::GetSettings()->PUSH_INFO_GROUP_CODE;
	std::string snd_msg = MATH::GetNowString() + " " + Settings::GetSettings()->RENDERER_ID;

#ifdef CONTROLLER
	snd_msg += "::CONTROLLER";
#elif defined AGENT
	snd_msg += "::AGENT";
#elif defined SCALER
	snd_msg += "::SCALER";
#endif

	snd_msg += "(" + Settings::GetSettings()->LOCAL_ADDR + ") ";

	if(_ERROR == mode)
	{
		group_code = Settings::GetSettings()->PUSH_ERROR_GROUP_CODE;
		snd_msg += "ERROR >> ";
	}
	snd_msg	+= msg;

	if(snd_msg.length() > 500)
		snd_msg = snd_msg.substr(0 , 500);


	std::string cmd = std::string("curl -d \"uuid=") + Settings::GetSettings()->PUSH_UUID
					 + "&secret_key="+Settings::GetSettings()->PUSH_SECRET_KEY
					 + "&code="+group_code
					 + "&body="+snd_msg+"\" "+Settings::GetSettings()->PUSH_URL;

#ifdef ACE_WIN32
	if( system((cmd + " >nul 2>&1").c_str()) != 0)
#else
	if( system((cmd + " >/dev/null 2>&1").c_str()) != 0)
#endif 
	{
		printf("push cmd error : %s\n" , cmd.c_str());
		return false;
	}
	
	return  true;

}


bool LOG::WriteProcessLog(const _LOG_MODE mode , const std::string& content)
{

	if(Settings::GetSettings()->LOG_TYPE == 'B' || Settings::GetSettings()->LOG_TYPE == 'b'
		|| Settings::GetSettings()->LOG_TYPE == 'F' || Settings::GetSettings()->LOG_TYPE == 'f')
	{
		WriteLog2File(_PROCESS_LOG ,mode , content);
	}

	if(Settings::GetSettings()->LOG_TYPE == 'B' || Settings::GetSettings()->LOG_TYPE == 'b'
		|| Settings::GetSettings()->LOG_TYPE == 'D' || Settings::GetSettings()->LOG_TYPE == 'd')
	{
		InsertProcessLog2DB(mode , content);
	}

	return true;

}

bool LOG::WriteJobLog(const _LOG_MODE mode , const std::string& job_id , const double duration , const int rendering_time, const std::string& content)
{

	if(Settings::GetSettings()->LOG_TYPE == 'B' || Settings::GetSettings()->LOG_TYPE == 'b'
		|| Settings::GetSettings()->LOG_TYPE == 'F' || Settings::GetSettings()->LOG_TYPE == 'f')
	{
		char buf[100];
		sprintf(buf , ",%.2f,%d," , duration , rendering_time);
		WriteLog2File(_JOB_LOG ,mode , job_id + buf + content);
	}

	if(Settings::GetSettings()->LOG_TYPE == 'B' || Settings::GetSettings()->LOG_TYPE == 'b'
		|| Settings::GetSettings()->LOG_TYPE == 'D' || Settings::GetSettings()->LOG_TYPE == 'd')
	{
		InsertJobLog2DB(mode , job_id , duration , rendering_time , content);
	}

	return true;

}

bool LOG::WriteObjectLog(const std::string& job_id , const std::string& filterId , const std::string& effectIdList , const std::string& soundId)
{


	if(Settings::GetSettings()->LOG_TYPE == 'B' || Settings::GetSettings()->LOG_TYPE == 'b'
		|| Settings::GetSettings()->LOG_TYPE == 'D' || Settings::GetSettings()->LOG_TYPE == 'd')
	{
		InsertObjectLog2DB(job_id , filterId , effectIdList , soundId);
	}

	return true;

}


bool LOG::WriteEC2Log(const _LOG_MODE mode , const std::string& ec2_id , const bool start)
{

	if(Settings::GetSettings()->LOG_TYPE == 'B' || Settings::GetSettings()->LOG_TYPE == 'b'
		|| Settings::GetSettings()->LOG_TYPE == 'F' || Settings::GetSettings()->LOG_TYPE == 'f')
	{
		char tmp[100];
		sprintf(tmp , "%s,%s" ,ec2_id.c_str() , start ? "START" : "STOP");
		WriteLog2File(_SCALING_LOG ,mode , tmp );
	}

	if(Settings::GetSettings()->LOG_TYPE == 'B' || Settings::GetSettings()->LOG_TYPE == 'b'
		|| Settings::GetSettings()->LOG_TYPE == 'D' || Settings::GetSettings()->LOG_TYPE == 'd')
	{
		InsertEC2Log2DB(mode , ec2_id , start);
	}

	return true;

}

bool LOG::WriteScalingLog(const _LOG_MODE mode ,const int waiting , const int changed , const int total)
{
	if(Settings::GetSettings()->LOG_TYPE == 'B' || Settings::GetSettings()->LOG_TYPE == 'b'
		|| Settings::GetSettings()->LOG_TYPE == 'F' || Settings::GetSettings()->LOG_TYPE == 'f')
	{
		char tmp[100];
		sprintf(tmp , "%d,%d,%d" ,waiting, changed , total);
		WriteLog2File(_SCALING_LOG ,mode , tmp );
	}

	if(Settings::GetSettings()->LOG_TYPE == 'B' || Settings::GetSettings()->LOG_TYPE == 'b'
		|| Settings::GetSettings()->LOG_TYPE == 'D' || Settings::GetSettings()->LOG_TYPE == 'd')
	{
		InsertScalingLog2DB(mode , waiting , changed , total);
	}

	return true;

}

std::string LOG::GetLogFilePath(const _LOG_TYPE type , const int pass )
{
	std::string dir;
	switch(type)
	{
	case _PROCESS_LOG:
		dir = Settings::GetSettings()->PROCESS_LOG_DIR;
		break;
	case _JOB_LOG:
		dir = Settings::GetSettings()->JOB_LOG_DIR;
		break;
	case _SCALING_LOG:
		dir = Settings::GetSettings()->SCALING_LOG_DIR; 
		break;
	}

	return dir + MATH::GetDateLogFileName(pass);

}

bool LOG::WriteLog2File(const _LOG_TYPE type , const _LOG_MODE mode ,  const std::string& content , const int pass )
{

	bool ret = true;
	std::string log_path = GetLogFilePath(type , pass);


	for(int i = 0 ; i < LOG_RETRY_COUNT ; i ++)
	{

		FILE * f = fopen(log_path.c_str() , "a");

		if(f)
		{
			std::string tmp;

			tmp = Settings::GetSettings()->RENDERER_ID;
			
			if(_INFO == mode)
				tmp += ",INFO";
			else if(_REQUIRED == mode)
				tmp += ",REQUIRED";
			else
				tmp += ",ERROR";

			int hour , min , sec;
			MATH::GetTime(hour , min , sec);
	char p = '?';


#ifdef CONTROLLER
	p = 'C';
#elif defined AGENT
	p = 'A';
#elif defined SCALER
	p = 'S';
#elif defined BACKUPMANAGER
	p = 'B';
#endif

	fprintf(f , "%d:%d:%d,%s,%c,%s\n" , hour , min , sec ,tmp.c_str(), p , content.c_str());

			fclose(f);

			ret = true;
			break;
		}
		else
		{
			sleep(1);
			ret = false;
			printf("retry to write log\n");
			continue;
		}
	}

	if(!ret)
	{
		printf("log writing failed\n");
	}

	return ret;
}


bool LOG::InsertProcessLog2DB(const _LOG_MODE mode , const std::string& content)
{
	if(content.length() == 0)
		return false;

	std::string sql = "INSERT INTO TBL_PROCESS_LOG( RENDERER_ID , PROCESS_TYPE , PROCESS_ADDR , LOG_MODE , CONTENTS) VALUES(?,?,?,?,?)";

	MYSQL_BIND param[5];
	memset (param, 0x00, sizeof (param)); 

	DBInterface::Match2StringValue(&param[0] , (char*)Settings::GetSettings()->RENDERER_ID.c_str() , Settings::GetSettings()->RENDERER_ID.length() , false);
	char p = '?';
#ifdef CONTROLLER
	p = 'C';
#elif defined AGENT
	p = 'A';
#elif defined SCALER
	p = 'S';
#elif defined BACKUPMANAGER
	p = 'B';
#endif
	DBInterface::Match2CharValue(&param[1] , &p);
	DBInterface::Match2StringValue(&param[2] , (char*)Settings::GetSettings()->LOCAL_ADDR.c_str() , Settings::GetSettings()->LOCAL_ADDR.length(), false);

	char m;
	if(_INFO == mode) 
		m = 'I';
	else if (_REQUIRED == mode) 
		m = 'R';
	else 
		m = 'E';
	DBInterface::Match2CharValue(&param[3] , &m);


	DBInterface::Match2StringValue(&param[4] , (char*)content.c_str() , content.length(), false);

	return DBInterface::Execute(sql , param);
}

bool LOG::InsertJobLog2DB(const _LOG_MODE mode , const std::string& job_id , double duration , int rendering_time ,  const std::string& content)
{
	if(job_id.length() == 0)
		return false;

	std::string sql = "INSERT INTO TBL_JOB_LOG( RENDERER_ID , PROCESS_TYPE , PROCESS_ADDR , LOG_MODE , JOB_ID , DURATION , RENDERING_TIME, CONTENTS) VALUES(?,?,?,?,?,ROUND(?,2),?,?)";	

	MYSQL_BIND param[8];
	memset (param, 0x00, sizeof (param)); 

	DBInterface::Match2StringValue(&param[0] , (char*)Settings::GetSettings()->RENDERER_ID.c_str() , Settings::GetSettings()->RENDERER_ID.length() , false);
	char p = '?';
#ifdef CONTROLLER
	p = 'C';
#elif defined AGENT
	p = 'A';
#elif defined SCALER
	p = 'S';
#elif defined BACKUPMANAGER
	p = 'B';
#endif
	DBInterface::Match2CharValue(&param[1] , &p);
	DBInterface::Match2StringValue(&param[2] , (char*)Settings::GetSettings()->LOCAL_ADDR.c_str() , Settings::GetSettings()->LOCAL_ADDR.length(), false);

	char m;
	if(_INFO == mode) 
		m = 'I';
	else if (_REQUIRED == mode) 
		m = 'R';
	else 
		m = 'E';
	DBInterface::Match2CharValue(&param[3] , &m);


	DBInterface::Match2StringValue(&param[4] , (char*)job_id.c_str() , job_id.length(), false);
	DBInterface::Match2DoubleValue(&param[5] , &duration);
	DBInterface::Match2IntValue(&param[6] , &rendering_time);
	DBInterface::Match2StringValue(&param[7] , (char*)content.c_str() , content.length(), false);


	return DBInterface::Execute( sql , param);
}

bool LOG::InsertObjectLog2DB(const std::string& job_id  , const std::string& filterId , const std::string& effectIdList , const std::string& soundId)
{
	if(job_id.length() == 0)
		return false;

	std::string sql = "call renderer_registerObjectLog(?,?,?,?)";	

	MYSQL_BIND param[4];
	memset (param, 0x00, sizeof (param)); 

	DBInterface::Match2StringValue(&param[0] , (char*)job_id.c_str() , job_id.length(), false);
	DBInterface::Match2StringValue(&param[1] , (char*)filterId.c_str() , filterId.length(), false);
	DBInterface::Match2StringValue(&param[2] , (char*)effectIdList.c_str() , effectIdList.length(), false);
	DBInterface::Match2StringValue(&param[3] , (char*)soundId.c_str() , soundId.length(), false);


	return DBInterface::Execute( sql , param);
}

bool LOG::InsertEC2Log2DB(const _LOG_MODE mode , const std::string& ec2_id , bool start)
{
	std::string sql = "INSERT INTO TBL_EC2_LOG( RENDERER_ID , PROCESS_TYPE , PROCESS_ADDR , LOG_MODE ,EC2_ID , OPERATION) VALUES(?,?,?,?,?,?) ";	

	MYSQL_BIND param[6];
	memset (param, 0x00, sizeof (param)); 

	DBInterface::Match2StringValue(&param[0] , (char*)Settings::GetSettings()->RENDERER_ID.c_str() , Settings::GetSettings()->RENDERER_ID.length() , false);
	char p = '?';
#ifdef CONTROLLER
	p = 'C';
#elif defined AGENT
	p = 'A';
#elif defined SCALER
	p = 'S';
#elif defined BACKUPMANAGER
	p = 'B';
#endif
	DBInterface::Match2CharValue(&param[1] , &p);
	DBInterface::Match2StringValue(&param[2] , (char*)Settings::GetSettings()->LOCAL_ADDR.c_str() , Settings::GetSettings()->LOCAL_ADDR.length(), false);

	char m;
	if(_INFO == mode) 
		m = 'I';
	else if (_REQUIRED == mode) 
		m = 'R';
	else 
		m = 'E';
	DBInterface::Match2CharValue(&param[3] , &m);

	DBInterface::Match2StringValue(&param[4] , (char*)ec2_id.c_str() , ec2_id.length(), false);

	char o;
	if(start)
		o = 'S';
	else
		o = 'E';
	DBInterface::Match2CharValue(&param[5] , &o);


	return DBInterface::Execute( sql , param);
}

bool LOG::InsertScalingLog2DB(const _LOG_MODE mode , int waiting , int changed , int total)
{
	if(changed == 0)
		return false;

	std::string sql = "INSERT INTO TBL_SCALING_LOG( RENDERER_ID , PROCESS_TYPE , PROCESS_ADDR , LOG_MODE ,WAITING_JOB_COUNT , CHANGED_INSTANCE_COUNT , TOTAL_INSTANCE_COUNT) VALUES(?,?,?,?,?,?,?)";	

	MYSQL_BIND param[7];
	memset (param, 0x00, sizeof (param)); 

	DBInterface::Match2StringValue(&param[0] , (char*)Settings::GetSettings()->RENDERER_ID.c_str() , Settings::GetSettings()->RENDERER_ID.length() , false);
	char p = '?';
#ifdef CONTROLLER
	p = 'C';
#elif defined AGENT
	p = 'A';
#elif defined SCALER
	p = 'S';
#elif defined BACKUPMANAGER
	p = 'B';
#endif
	DBInterface::Match2CharValue(&param[1] , &p);
	DBInterface::Match2StringValue(&param[2] , (char*)Settings::GetSettings()->LOCAL_ADDR.c_str() , Settings::GetSettings()->LOCAL_ADDR.length(), false);

	char m;
	if(_INFO == mode) 
		m = 'I';
	else if (_REQUIRED == mode) 
		m = 'R';
	else 
		m = 'E';
	DBInterface::Match2CharValue(&param[3] , &m);


	DBInterface::Match2IntValue(&param[4] , &waiting);
	DBInterface::Match2IntValue(&param[5] , &changed);
	DBInterface::Match2IntValue(&param[6] , &total);


	return DBInterface::Execute( sql , param);
}

void _JOB_INFO::SetResolution(Json::Value& root)
{
	int w = PACKET_BASE::GetIntS(root["resolution"] , "width");
	int h = PACKET_BASE::GetIntS(root["resolution"] , "height");

	if(w == Settings::GetSettings()->HIGH_WIDTH && h == Settings::GetSettings()->HIGH_HEIGHT)
	{
		highResolution = _RESOLUTION(Settings::GetSettings()->HIGH_WIDTH , Settings::GetSettings()->HIGH_HEIGHT);
		middleResolution = _RESOLUTION(Settings::GetSettings()->MIDDLE_WIDTH , Settings::GetSettings()->MIDDLE_HEIGHT);
		lowResolution = _RESOLUTION(Settings::GetSettings()->LOW_WIDTH , Settings::GetSettings()->LOW_HEIGHT);

		SetBV(Settings::GetSettings()->HIGH_BITRATE, Settings::GetSettings()->MIDDLE_BITRATE, Settings::GetSettings()->LOW_BITRATE);
		SetBA(Settings::GetSettings()->HIGH_AUDIO_BITRATE, Settings::GetSettings()->MIDDLE_AUDIO_BITRATE, Settings::GetSettings()->LOW_AUDIO_BITRATE);
	}
	else if(w == Settings::GetSettings()->MIDDLE_WIDTH && h == Settings::GetSettings()->MIDDLE_HEIGHT)
	{
		highResolution = _RESOLUTION(Settings::GetSettings()->MIDDLE_WIDTH , Settings::GetSettings()->MIDDLE_HEIGHT);
		middleResolution = _RESOLUTION(Settings::GetSettings()->LOW_WIDTH , Settings::GetSettings()->LOW_HEIGHT);
		lowResolution = _RESOLUTION(0,0);

		SetBV(Settings::GetSettings()->MIDDLE_BITRATE, Settings::GetSettings()->LOW_BITRATE, 0);
		SetBA(Settings::GetSettings()->MIDDLE_AUDIO_BITRATE, Settings::GetSettings()->LOW_AUDIO_BITRATE, 0);
	}
	else if(w == Settings::GetSettings()->HIGH_WIDTH2 && h == Settings::GetSettings()->HIGH_HEIGHT2)
	{
		highResolution = _RESOLUTION(Settings::GetSettings()->HIGH_WIDTH2 , Settings::GetSettings()->HIGH_HEIGHT2);
		middleResolution = _RESOLUTION(Settings::GetSettings()->MIDDLE_WIDTH2 , Settings::GetSettings()->MIDDLE_HEIGHT2);
		lowResolution = _RESOLUTION(Settings::GetSettings()->LOW_WIDTH2 , Settings::GetSettings()->LOW_HEIGHT2);

		SetBV(Settings::GetSettings()->HIGH_BITRATE, Settings::GetSettings()->MIDDLE_BITRATE, Settings::GetSettings()->LOW_BITRATE);
		SetBA(Settings::GetSettings()->HIGH_AUDIO_BITRATE, Settings::GetSettings()->MIDDLE_AUDIO_BITRATE, Settings::GetSettings()->LOW_AUDIO_BITRATE);
	}
	else if(w == Settings::GetSettings()->MIDDLE_WIDTH2 && h == Settings::GetSettings()->MIDDLE_HEIGHT2)
	{
		highResolution = _RESOLUTION(Settings::GetSettings()->MIDDLE_WIDTH2 , Settings::GetSettings()->MIDDLE_HEIGHT2);
		middleResolution = _RESOLUTION(Settings::GetSettings()->LOW_WIDTH2 , Settings::GetSettings()->LOW_HEIGHT2);
		lowResolution = _RESOLUTION(0,0);

		SetBV(Settings::GetSettings()->MIDDLE_BITRATE, Settings::GetSettings()->LOW_BITRATE, 0);
		SetBA(Settings::GetSettings()->MIDDLE_AUDIO_BITRATE, Settings::GetSettings()->LOW_AUDIO_BITRATE, 0);
	}

	else
	{
		highResolution = _RESOLUTION(854 , 480);
		middleResolution = _RESOLUTION(640 , 360);
		lowResolution = _RESOLUTION(0,0);

		SetBV(1800, 1200, 0);
		SetBA(128, 64, 0);
	}


}